#include	<Network.h>
#include	<cstdio>
#include	<cstring>
#include	<vector>

static char * GNetRecvBuffer = new char[2097152];
static uint64_t GNetAllocId = 0;

//////////////////////////////////////////////////////////////////////////
/// IMPLEMENTS OF IConnector
//////////////////////////////////////////////////////////////////////////

IConnector::IConnector()
	: _pSocket(Network::CreatePlatformSocket()) {
	_pSocket->pListener = this;
}

IConnector::~IConnector() {
	delete _pSocket;
}

bool IConnector::Connect(const std::string & sIP, int nPort) {
	return _pSocket->Connect(sIP, nPort);
}

void IConnector::Close(int nReason /* = NET_CLOSE_LOCAL */) {
	_pSocket->Close(nReason);
}

bool IConnector::Send(const char * pData, size_t nSize) {
	if (!pData || nSize <= 0) return true;
	return _pSocket->Send(pData, nSize);
}

void IConnector::OnProcess(int nEvent, int nData) {
	if (nEvent == NET_EVENT_CONNECTED) {
		OnConnected();
	} else if (nEvent == NET_EVENT_CLOSED) {
		OnClose(nData);
	} else if (nEvent == NET_EVENT_READABLE) {
		memset(GNetRecvBuffer, 0, 2097152);

		int nReaded = 0;
		int nRecv = 0;

		while (true) {
			nRecv = _pSocket->Recv(GNetRecvBuffer + nReaded, 2097152 - nReaded);
			if (nRecv > 0) {
				nReaded += nRecv;
				if (nReaded >= 2097152) {
					OnReceive(GNetRecvBuffer, nReaded);
					memset(GNetRecvBuffer, 0, 2097152);
					nReaded = 0;
				}
			} else if (nRecv == NET_RECV_PENDING) {
				if (nReaded > 0) OnReceive(GNetRecvBuffer, nReaded);
				break;
			} else {
				if (nReaded > 0) OnReceive(GNetRecvBuffer, nReaded);
				_pSocket->Close(nRecv == NET_RECV_CLOSED ? NET_CLOSE_REMOTE : NET_CLOSE_ERROR);
				break;
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
/// IMPLEMENTS OF Connection
//////////////////////////////////////////////////////////////////////////

Connection::Connection(IService * pOwner, ISocket * pSocket, uint64_t nId, uint32_t nIP)
	: _pOwner(pOwner)
	, _pSocket(pSocket)
	, _nId(nId)
	, _sIP{ 0 }
	, _pAttached(nullptr) {
	int n1 = (nIP & 0xFF);
	int n2 = (nIP >> 8) & 0xFF;
	int n3 = (nIP >> 16) & 0xFF;
	int n4 = (nIP >> 24) & 0xFF;
	snprintf(_sIP, 16, "%d.%d.%d.%d", n1, n2, n3, n4);
	_pSocket->pListener = this;
}

Connection::~Connection() {
	delete _pSocket;
}

void Connection::OnProcess(int nEvent, int nData) {
	if (nEvent == NET_EVENT_CLOSED) {
		_pOwner->OnClose(this, nData);

		auto it = _pOwner->_mConns.find(_nId);
		if (it != _pOwner->_mConns.end()) _pOwner->_mConns.erase(it);
		delete this;
	} else if (nEvent == NET_EVENT_READABLE) {
		memset(GNetRecvBuffer, 0, 2097152);

		int nReaded = 0;
		int nRecv = 0;

		while (true) {
			nRecv = _pSocket->Recv(GNetRecvBuffer + nReaded, 2097152 - nReaded);
			if (nRecv > 0) {
				nReaded += nRecv;
				if (nReaded >= 2097152) {
					_pOwner->OnReceive(this, GNetRecvBuffer, nReaded);
					memset(GNetRecvBuffer, 0, 2097152);
					nReaded = 0;
				}
			} else if (nRecv == NET_RECV_PENDING) {
				if (nReaded > 0) _pOwner->OnReceive(this, GNetRecvBuffer, nReaded);
				break;
			} else {
				if (nReaded > 0) _pOwner->OnReceive(this, GNetRecvBuffer, nReaded);
				_pSocket->Close(nRecv == NET_RECV_CLOSED ? NET_CLOSE_REMOTE : NET_CLOSE_ERROR);
				break;
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
/// IMPLEMENTS OF IService
//////////////////////////////////////////////////////////////////////////

IService::IService() : _pSocket(Network::CreatePlatformSocket()) {
	_pSocket->pListener = this;
}

IService::~IService() {
	Shutdown();
	delete _pSocket;
}

int IService::Listen(const std::string & sIP, int nPort) {
	return _pSocket->Listen(sIP, nPort);
}

Connection * IService::Find(uint64_t nConnId) const {
	auto it = _mConns.find(nConnId);
	if (it == _mConns.end()) return nullptr;
	return it->second;
}

void IService::Broadcast(const char * pData, size_t nSize) {
	for (const auto & kv : _mConns) kv.second->Send(pData, nSize);
}

void IService::Shutdown() {
	std::vector<Connection *> lConns;
	for (const auto & kv : _mConns) lConns.push_back(kv.second);
	for (auto p : lConns) p->Close();
	_pSocket->Close(NET_CLOSE_LOCAL);
}

void IService::OnProcess(int nEvent, int nData) {
	if (nEvent == NET_EVENT_READABLE) {
		while (true) {
			uint32_t nIP = 0;
			ISocket * pAccept = _pSocket->Accept(nIP);
			if (!pAccept) break;

			Connection * pConn = new Connection(this, pAccept, ++GNetAllocId, nIP);
			pAccept->pListener = pConn;
			_mConns[pConn->Id()] = pConn;
			OnAccept(pConn);
		}
	} else if (nEvent == NET_EVENT_CLOSED) {
		OnShutdown();
	}
}